﻿// Copyright (c) 2009 Paul Kohler
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
// and associated documentation files (the "Software"), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 
// so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or substantial 
// portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using Ionic.Zip;
using Newtonsoft.Json;

namespace FileSystemDatabase
{
	public class JsonDatabase : FileSystemDatabase
	{
		private static readonly object syncLock = new object();

		public JsonDatabase(string basePath)
			: base(basePath)
		{
			FileExtension = "json";
			
			DirectoryInfo dir = new DirectoryInfo(basePath);
			if(!dir.Exists)
			{
				dir.Create();
			}
		}

		public override string Write<T>(T row, string id)
		{
			string filename = CreateFilename(typeof(T), id);
			Formatting formatting = Formatting.None;
			if (WriteIndented)
			{
				formatting = Formatting.Indented;
			}
			string output = JsonConvert.SerializeObject(row, formatting);

			lock (syncLock)
			{
				File.WriteAllText(filename, output);
			}

			return filename;
		}

		public override T Read<T>(string id)
		{
			string filename = CreateFilename(typeof(T), id);
			return InternalRead<T>(filename);
		}

		protected override T InternalRead<T>(string filename)
		{
			if (File.Exists(filename))
			{
				string fileData = File.ReadAllText(filename);
				return (T) JsonConvert.DeserializeObject(fileData, typeof(T));
			}
			return default(T);
		}

		public override T[] Read<T>()
		{
			string filePattern = string.Format("{0}-*.{1}", typeof(T).Name, FileExtension);
			string[] files = Directory.GetFiles(BasePath, filePattern, SearchOption.TopDirectoryOnly);
			List<T> list = new List<T>();
			foreach (string filename in files)
			{
				list.Add(InternalRead<T>(filename));
			}
			return list.ToArray();
		}

		public override void Delete<T>(string id)
		{
			Delete(typeof(T), id);
		}

		public override void Delete(Type type, string id)
		{
			string filename = CreateFilename(type, id);
			if (File.Exists(filename))
			{
				File.Delete(filename);
			}
		}

		public override string CreateBackup(string zipName)
		{
			string zipFilename = Path.Combine(BasePath, zipName);

			using (ZipFile zip = new ZipFile())
			{
				lock (syncLock)
				{
					string filePattern = string.Format("*-*.{0}", FileExtension);
					string[] files = Directory.GetFiles(BasePath, filePattern, SearchOption.TopDirectoryOnly);
					foreach (string filename in files)
					{
						zip.AddFile(filename, string.Empty);
					}
					zip.Save(zipFilename);
				}

				return zipFilename;
			}
		}
	}
}